#ifndef __TASKTAG__
#define __TASKTAG__

#include <array>
#include <tuple>
#include <iostream>

#include "TupleHelper.hpp"
#include "constants.h"

using namespace std;

template<int TASK_ID, int TASKTAGDIM, int TASKDIM>
class TaskTag {
public:
  const int id = TASK_ID;

  std::array<int64_t, TASKTAGDIM> m_arr;

  TaskTag() = delete;

  template <typename... Sizes> constexpr 
  TaskTag(Sizes... sizes) : m_arr{{std::forward<Sizes>(sizes)...}}{
    static_assert(TASKTAGDIM == sizeof...(Sizes), "ERROR");
  }

  constexpr TaskTag(std::array<int64_t, TASKTAGDIM> arr) : m_arr(arr) {}

  constexpr auto toTuple() const -> 
    decltype(arrayAsTuple<int64_t, TASKTAGDIM>::make(m_arr)) 
  {
    return arrayAsTuple<int64_t, TASKTAGDIM>::make(m_arr);
  }

  constexpr TaskTag(const TaskTag &tt) : m_arr(tt.m_arr) {}  

  constexpr bool operator==(const TaskTag &tt) const {
    return (tt.m_arr == m_arr);
  }

  constexpr operator size_t() const {
    return TASKTAGDIM * sizeof (int64_t);
  }

  // Find a workaround to make this constexpr
  // See for instance: https://gist.github.com/1457531
  int64_t operator[](int64_t i) const {
    return m_arr[i];
  }
};


template<int TASK_ID, int TASKTAGDIM, int TASKDIM>
ostream& operator<<(ostream& stream, TaskTag<TASK_ID, TASKTAGDIM, TASKDIM> const &tt);
#endif // __TASKTAG__
